﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace BlockingCollectionConsoleApp
{
    public static class ProducerConsumerQueue2
    {

        [DllImport("kernel32.dll")] 
        private static extern uint GetCurrentProcessorNumber();

        public static void Run()
        {
            var blockingCollection = new BlockingCollection<int>();
            var tasks = new List<Task>();

            Console.WriteLine("Defining tasks");

            // create many consumers
            for (var i = 0; i < 10; i++)
            {
                var consumerIndex = i;
                
                tasks.Add(new Task(() =>
                {
                    Console.WriteLine("Starting consumer {0} on thread {1} using CPU {2}", consumerIndex, Thread.CurrentThread.ManagedThreadId, GetCurrentProcessorNumber());
                    foreach (var itemToConsume in blockingCollection.GetConsumingEnumerable())
                    {
                        Console.WriteLine("Consumer {0} processing {1} on thread {2} using CPU {3}", consumerIndex, itemToConsume, Thread.CurrentThread.ManagedThreadId, GetCurrentProcessorNumber());
                        Thread.Sleep(5000);
                    }
                }));
            }

            // create one producer
            tasks.Add(new Task(() =>
            {
                Console.WriteLine("Starting producer on thread {0} using CPU {1}", Thread.CurrentThread.ManagedThreadId, GetCurrentProcessorNumber());
                for (var i = 0; i < 50; i++)
                {
                    blockingCollection.Add(i);
                }
                blockingCollection.CompleteAdding();
            }));

            Console.WriteLine("Starting tasks");
            tasks.ForEach(t => t.Start());

            Console.WriteLine("Waiting for all tasks to complete");
            Task.WaitAll(tasks.ToArray());

            Console.WriteLine("All tasks complete");
            Console.ReadLine();

        }
    }
}
